
#include "NetListener.h"

#include "CommandHandler.h"

//The NetListener actively listens to input that comes from the network via the IP protocol. In SphereX, these inputs are meant
//to come from mobile devices to define physcial parameters of the game.


//The constructor, taking a reference to the command handler
NetListener::NetListener(CommandHandler *commandHandler){
		this->commandHandler = commandHandler;
		host_port=PORT;
		addr_size = sizeof(SOCKADDR);
		wVersionRequested = MAKEWORD( 2, 0 );
}

//Destructor
NetListener::~NetListener(){
}


//Listen actively to inputs over the network
void NetListener::startListening(void){
	fprintf(stdout, "Called method to start listening...\n");

	//Initialize operating-system related settings
    wVersionRequested = MAKEWORD( 2, 2 );
     err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 || ( LOBYTE( wsaData.wVersion ) != 2 ||
            HIBYTE( wsaData.wVersion ) != 2 )) {
        fprintf(stdout, "Could not find useable sock dll %d\n",WSAGetLastError());
		//std::wcout<<"Could not find usable sock dll."<<std::endl;
        goto FINISH;
    }

    //Initialize sockets and set the appropriate options in order to receive commands from mobiles
    int hsock;
    int * p_int ;
    hsock = socket(AF_INET, SOCK_STREAM, 0);
    if(hsock == -1){
        fprintf(stdout, "Error initializing socket %d\n",WSAGetLastError());
		//std::wcout<<"Could not initialize socket."<<std::endl;
        goto FINISH;
    }
    p_int = (int*)malloc(sizeof(int));
    *p_int = 1;
    if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
        (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
        fprintf(stdout, "Error setting options %d\n", WSAGetLastError());
		//std::wcout<<"Could not set options."<<std::endl;
        free(p_int);
        goto FINISH;
    }
    free(p_int);
    my_addr.sin_family = AF_INET ;
    my_addr.sin_port = htons(host_port);
    memset(&(my_addr.sin_zero), 0, 8);
    my_addr.sin_addr.s_addr = INADDR_ANY ;
    
	//Bind to the socket
    if( bind( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
        fprintf(stdout,"Error binding to socket, make sure nothing else is listening on this port %d\n",WSAGetLastError());
		//std::wcout<<"Could not bind to socket. Try another port."<<std::endl;
        goto FINISH;
    }
    if(listen( hsock, 10) == -1 ){
        fprintf(stdout, "Error listening %d\n",WSAGetLastError());
		//std::wcout<<"Could not listen to socket."<<std::endl;
        goto FINISH;
    }
    
   //Start read own address
	   if ( WSAStartup( wVersionRequestedIp, &wsaDataIp ) == 0 )
      {
            if( gethostname ( name, sizeof(name)) == 0)
            {
                  if((hostinfo = gethostbyname(name)) != NULL)
                  {
                        ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
                  }
            }
            WSACleanup( );
      } 
	//End read own address

	   fprintf(stdout, "\n----------\nStarting to listen on %s:%d\n", ip, host_port);
	//std::wcout<<"\n----------\nStarting to listen on "<<ip<<":"<<host_port<<"\n"<<std::endl;
    
	   //In the while loop, the socket listens all the time for a connection initiated by the client
    while(true){
        //fprintf(stdout, "\n----------\nwaiting for a connection\n");
		//std::wcout<<"\n----------\nwaiting for a connection\n"<<std::endl;
        csock = (int*)malloc(sizeof(int));
        
        if((*csock = accept( hsock, (SOCKADDR*)&sadr, &addr_size))!= INVALID_SOCKET ){
            //fprintf(stdout, "Received connection from %s",inet_ntoa(sadr.sin_addr));
			//std::wcout<<"Connection established with "<<inet_ntoa(sadr.sin_addr)<<std::endl;

			SocketHandlingStruct *shs = new SocketHandlingStruct;
			shs->csock=csock;
			shs->commandHandler=commandHandler;

            //CreateThread(0,0,&SocketHandler, (void*)csock , 0,0);
			CreateThread(0,0,&SocketHandler, (void*)shs , 0,0);
        }
        else{
            fprintf(stdout, "Error accepting %d\n",WSAGetLastError());
			//std::wcout<<"Could not set accept socket input."<<std::endl;
        }
    }

FINISH:
	//Cleanup
;
}


/*
This is the method were the actual received data is being interpreted and sent to the command handler using the appropriate method
*/
DWORD WINAPI SocketHandler(void* lp){
    //int *csock = (int*)lp;
	SocketHandlingStruct *shs = reinterpret_cast<SocketHandlingStruct*>(lp);
	int *csock = shs->csock;
	CommandHandler *commandHandler=shs->commandHandler;

    char buffer[1024];
    int buffer_len = 1024;
    int bytecount;

    memset(buffer, 0, buffer_len);
    if((bytecount = recv(*csock, buffer, buffer_len, 0))==SOCKET_ERROR){
        fprintf(stdout, "Error receiving data %d\n", WSAGetLastError());
		//std::wcout<<"Could not receive data."<<std::endl;
        goto FINISH;
    }
    //fprintf(stdout, "Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
	//std::wcout<<"Received "<<bytecount<<" bytes: '"<<buffer<<"'"<<std::endl;
    //strcat(buffer, " SERVER ECHO");

	if(strchr(buffer, ':')!=NULL){
		char *physics = strtok(buffer, ":");
		float value = atof(strtok(NULL, "\n"));
		fprintf(stdout, "Physics: %s\tValue: %3.2f\n", physics, value);
		if(!strcmp("Gravity", physics))
			commandHandler->setPhysics(false, GRAVITY, value);
		else if(!strcmp("Bounce", physics))
			commandHandler->setPhysics(false, BOUNCE, value);
		else if(!strcmp("Friction", physics))
			commandHandler->setPhysics(false, FRICTION, value);

	}
	//Sending methods (not used)
    //if((bytecount = send(*csock, buffer, strlen(buffer), 0))==SOCKET_ERROR){
    //    fprintf(stderr, "Error sending data %d\n", WSAGetLastError());
    //    goto FINISH;
    //}
    //
    //fprintf(stdout, "Sent bytes %d\n", bytecount);


FINISH:
    free(csock);
    return 0;
}   




